/**
 * Copyright (C) 2017 - 2020 https://github.com/joewee
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bifrost.service.impl;

import com.alibaba.fastjson.JSON;
import com.bifrost.constant.RunningMode;
import com.bifrost.entity.Order;
import com.bifrost.entity.OrderTransaction;
import com.bifrost.entity.RefundRequest;
import com.bifrost.exception.BonusPointsNotEnoughException;
import com.bifrost.exception.RollbackBonuspointsException;
import com.bifrost.repository.OrderTransactionRepository;
import com.bifrost.repository.RefundRequestRepository;
import com.bifrost.service.*;
import com.bifrost.uid.UidGenerator;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Map;
import java.util.TreeMap;

/**
 * @author joewee
 * @version 1.0.0
 * @Date 2017/12/4 13:01
 */
@Service
public class WechatPayServiceImpl implements PayGatewayService {
    private static final Logger LOGGER = LoggerFactory.getLogger(WechatPayServiceImpl.class);
    @Autowired
    OrderService orderService;
    @Autowired
    WxPayService wxPayService;
    @Autowired
    CustomerService customerService;
    @Autowired
    CouponService couponService;
    @Autowired
    SmsService smsService;
    @Autowired
    OrderTransactionRepository orderTransactionRepository;
    @Autowired
    RefundRequestRepository refundRequestRepository;
    @Autowired
    UidGenerator uidGenerator;
    @Autowired
    OrderStatusHistoryService statusHistoryService;
    @Value("${running.mode:#{null}}")
    private String runningMode;

    /**
     * 统一下单
     *
     * @param request
     * @return
     */
    @Override
    public Map<String, String> unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
        Order order = orderService.findOrderByOutTradeNo(request.getOutTradeNo());
        if (order == null) {
            throw new WxPayException("订单异常");
        }
        WxPayUnifiedOrderResult result = wxPayService.unifiedOrder(request);
        String appId = result.getAppid();
        long stamp = System.currentTimeMillis();
        Map<String, String> parameters = new TreeMap<String, String>();
        parameters.put("appId", result.getAppid());
        parameters.put("timeStamp", String.format("%d", stamp));
        parameters.put("nonceStr", String.format("%d", stamp));
        parameters.put("package", String.format("prepay_id=%s", result.getPrepayId()));
        parameters.put("signType", wxPayService.getConfig().getSignType());
        String sign = SignUtils.createSign(parameters, wxPayService.getConfig().getSignType(), wxPayService.getConfig().getMchKey(), false);
        parameters.put("paySign", sign);
        //记录订单交易事件日志
        OrderTransaction transaction = new OrderTransaction();
        transaction.setOrder(order);
        transaction.setPaymentType(order.getPayment().getDescription());
        transaction.setTransactionAmount(request.getTotalFee().toString());
        transaction.setTransactionDate(new Date());
        transaction.setTransactionType("unifiedorder");
        transaction.setUpdatedTimestamp(new Date());
        transaction.setTransactionDetails(JSON.toJSONString(result));
        transaction.setBusinessId(result.getPrepayId());
        orderTransactionRepository.save(transaction);
        return parameters;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void refund(RefundRequest refundRequest) throws WxPayException {
        //取消原订单
        Order order = orderService.findOrderByOutTradeNo(refundRequest.getOutTradeNumber());
        boolean result = false;
        try {
            orderService.rollback(order);
        } catch (RollbackBonuspointsException e) {
            throw new RuntimeException("取消订单失败");
        } catch (BonusPointsNotEnoughException e) {
            throw new RuntimeException("取消订单失败");
        }
        if (!result) {
            throw new RuntimeException("取消订单失败");
        }
        if (refundRequest.getRefundFee() > 0) {
            WxPayRefundRequest request = WxPayRefundRequest.newBuilder()
                    .outTradeNo(refundRequest.getOutTradeNumber())
                    .refundFee(refundRequest.getRefundFee())
                    .totalFee(refundRequest.getOrderTotalFee())
                    .refundDesc(refundRequest.getRefundDesc())
                    .build();
            if (RunningMode.DEVELOPMENT.equalsIgnoreCase(runningMode)) {
                request.setRefundFee(1);
                request.setTotalFee(1);
            }
            if (StringUtils.isNotEmpty(refundRequest.getRefundNumber())) {
                request.setOutRefundNo(refundRequest.getRefundNumber());
            } else {
                request.setOutRefundNo(String.format("%d", uidGenerator.getUID()));
            }
            try {
                WxPayRefundResult refundResult = wxPayService.refund(request);
                //记录订单交易事件日志
                OrderTransaction transaction = new OrderTransaction();
                transaction.setOrder(order);
                transaction.setPaymentType(order.getPayment().getDescription());
                transaction.setTransactionAmount(request.getTotalFee().toString());
                transaction.setTransactionDate(new Date());
                transaction.setTransactionType("refund");
                transaction.setUpdatedTimestamp(new Date());
                transaction.setTransactionDetails(JSON.toJSONString(refundResult));
                transaction.setBusinessId(refundResult.getRefundId());
                orderTransactionRepository.save(transaction);
                if (refundResult.getReturnCode().equalsIgnoreCase("SUCCESS")) {
                    refundRequest.setSuccess(Boolean.TRUE);
                    statusHistoryService.writeHistory(order, "退款成功", Boolean.TRUE,null);
                    //  发送通知短信
                    String phone = order.getCustomer().getCustomerPhone();
                    if (StringUtils.isNotEmpty(phone)) {
                        smsService.sendCustomerMessage(phone, String.format("您编号为%s退款申请已经为您处理，系统将在24小时内将退款返回您的付款账户！", order.getOrderNumber()));
                    }
                }
                refundRequest.setRefundNumber(request.getOutRefundNo());
                refundRequestRepository.save(refundRequest);
            } catch (WxPayException e) {
                LOGGER.error(e.getMessage(), e);
                throw e;
            }
        } else {
            refundRequest.setSuccess(Boolean.TRUE);
            refundRequestRepository.save(refundRequest);
        }
    }
}
